/*
 * Copyright (C) 2008+ Spark Zheng
 *
 * test_seqtree.c
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include <sys/time.h>
#include <stdint.h>
#include <sys/types.h>
#include <pthread.h>

#include "tree.h"
#include "timer.h"

typedef struct test_seqtree S_TEST_SEQNODE;
typedef struct test_seqhead S_TEST_SEQHEAD;

struct test_seqtree {
	int key;
	char *value;
	rbtree_node_t seqnode;
};

struct test_seqhead {
	pthread_mutex_t seqhead_mutex;
	rbtree_head_t seqhead;
};

static int compare_fn(const void *one, const void *two);
static void walker_fn(rbtree_node_t * node, void *arg);

int main(int argc, char **argv)
{
	int i;
	int ret;
	int32_t ks;
	int32_t vs;

	struct timeval start, end, result;

	S_TEST_SEQHEAD test_head;
	S_TEST_SEQNODE test_data[100];

	ks = (int32_t) & (test_data[0].seqnode) - (int32_t) & (test_data[0].key);
	vs = (int32_t) & (test_data[0].seqnode) - (int32_t) & (test_data[0].value);

	fprintf(stderr, "TEST_SEQTREE: KS is %d, VS is %d\n", ks, vs);

	ret = rb_init(&test_head.seqhead, compare_fn, ks, vs);

if (argc < 2 || strcasecmp(argv[1], "p") != 0) {

	srand(time(NULL));
	for (i = 0; i < 100; i++) {
		test_data[i].key = rand() % 1000;
	//      test_data[i].key = i;
		test_data[i].value = NULL;
	}

	for (i = 0; i < 100; i++) {
		fprintf(stderr, "key is %d\n", test_data[i].key);
		ret = rb_insert(&test_head.seqhead, &(test_data[i].seqnode), RB_EXACT);
		if (ret < 0 && ret != -10)
			fprintf(stderr, "key %d insert err\n", test_data[i].key);

	}

	int find_key = 66;
	rbtree_node_t *tmp;
	rbtree_node_t *pre;
	rbtree_node_t *suc;
	rbtree_node_t *min;
	rbtree_node_t *max;
	rbtree_node_t *del;

	tmp = rb_find(&test_head.seqhead, NULL, RB_SEARCH_EQ, (void *)&find_key);
	if (tmp != NULL) {
		pre = rb_predecessor(tmp);
		fprintf(stderr, "pre key of %d is %d\n",
			(RB_ENTRY(tmp, S_TEST_SEQNODE, seqnode))->key,
			(RB_ENTRY(pre, S_TEST_SEQNODE, seqnode))->key);
		suc = rb_successor(tmp);
		fprintf(stderr, "suc key of %d is %d\n",
			(RB_ENTRY(tmp, S_TEST_SEQNODE, seqnode))->key,
			(RB_ENTRY(suc, S_TEST_SEQNODE, seqnode))->key);

		min = rb_minimum(RB_ROOT(&test_head.seqhead));
		fprintf(stderr, "min key is %d\n",
			(RB_ENTRY(min, S_TEST_SEQNODE, seqnode))->key);
		max = rb_maximum(RB_ROOT(&test_head.seqhead));
		fprintf(stderr, "max key is %d\n",
			(RB_ENTRY(max, S_TEST_SEQNODE, seqnode))->key);
	}

	tmp = rb_find(&test_head.seqhead, NULL, RB_SEARCH_GE, (void *) &find_key);

	if (tmp == NULL) {
		fprintf(stderr, "find key %d not exist\n", find_key);
	} else {
		del = rb_delete(&test_head.seqhead, tmp);
		fprintf(stderr, "del key is %d\n",
			(RB_ENTRY(del, S_TEST_SEQNODE, seqnode))->key);
	}

	fprintf(stderr, "before del key is %d\n",
		(RB_ENTRY(RB_ROOT(&test_head.seqhead), S_TEST_SEQNODE, seqnode))-> key);

	del = rb_delete(&test_head.seqhead, RB_ROOT(&test_head.seqhead));
	fprintf(stderr, "del key is %d\n", 
		(RB_ENTRY(del, S_TEST_SEQNODE, seqnode))->key);

	tmp = rb_select(RB_ROOT(&test_head.seqhead), 20);
	if (tmp == NULL) {
		fprintf(stderr, "select 20-th node not exist\n");
	} else {
		del = rb_delete(&test_head.seqhead, tmp);
		fprintf(stderr, "del key is %d, size is %u\n",
			(RB_ENTRY(del, S_TEST_SEQNODE, seqnode))->key, RB_SIZE(del));
	}
	tmp = rb_select(RB_ROOT(&test_head.seqhead), 20);
	if (tmp == NULL) {
		fprintf(stderr, "[AFTER DEL]select 20-th node not exist\n");
	} else {
		fprintf(stderr, "[AFTER DEL]20-th node key is %d, size is %u\n",
			(RB_ENTRY(tmp, S_TEST_SEQNODE, seqnode))->key, RB_SIZE(tmp));
	}

	uint32_t rank;
	rank = rb_rank(RB_ROOT(&test_head.seqhead), tmp);
	if (rank == 0) {
		fprintf(stderr, "unexpect: tmp[%p] not in rank\n", tmp);
	} else {
		fprintf(stderr, "rank tmp[%p][%d] is %u\n", tmp,
			(RB_ENTRY(tmp, S_TEST_SEQNODE, seqnode))->key, rank);
	}
	rank = rb_rank(tmp, tmp);
	fprintf(stderr, "rank itself: tmp[%p] is %u\n", tmp, rank);
	
	rank = rb_revrank(RB_ROOT(&test_head.seqhead), tmp);
	if (rank == 0) {
		fprintf(stderr, "unexpect: tmp[%p] not in revrank\n", tmp);
	} else {
		fprintf(stderr, "revrank tmp[%p][%d] is %u\n", tmp,
			(RB_ENTRY(tmp, S_TEST_SEQNODE, seqnode))->key, rank);
	}

	char *arg = "function-test";

	ret = rb_inorder(&test_head.seqhead, walker_fn, (void *) arg);

} 

if (argc >= 2 && strcasecmp(argv[1], "p") == 0) {
	uint32_t count = 0;
	uint32_t count_init = 0;
	if (argc >= 3) count = (uint32_t)atoi(argv[2]);
	if (count == 0) count = 100000;
	count_init = count;

	fprintf(stdout, "press-test count is %u.\n", count);

	srand(time(NULL));
	DLIB_UTIMER_RECORD(&start);
	while(--count > 0) {
		S_TEST_SEQNODE *test_pdata = NULL;
		while ((test_pdata = (S_TEST_SEQNODE *)malloc(sizeof(*test_pdata))) == NULL);
		test_pdata->key = rand() % (count * 10);
		test_pdata->value = NULL;

		ret = rb_insert(&test_head.seqhead, &(test_pdata->seqnode), RB_EXACT);
		if (ret < 0 && ret != -10)
			fprintf(stderr, "[%d]key %d insert err\n", ret, test_pdata->key);
	}
	DLIB_UTIMER_RECORD(&end);

	//char *arg = "press-test";
	//ret = rb_inorder(&test_head.seqhead, walker_fn, (void *) arg);
	
	DLIB_UTIMER_SUB(&end, &start, &result);
	fprintf(stderr, "[s]press test for seqtree: time %06f for %d counts\n",
		result.tv_sec + (float) result.tv_usec / 1000000, count_init);
}

	rb_exit(&test_head.seqhead, NULL, NULL);

	return 0;
}

int compare_fn(const void *one, const void *two)
{
	int a = *((const int *) one);
	int b = *((const int *) two);

	if (a == b) {
//		fprintf(stderr, "EQ, a = %d, b = %d\n", a, b);
		return 0;
	} else if (a < b) {
//		fprintf(stderr, "LT, a = %d, b = %d\n", a, b);
		return -1;
	} else {
//		fprintf(stderr, "GT, a = %d, b = %d\n", a, b);
		return 1;
	}
}

void walker_fn(rbtree_node_t *node, void *arg)
{
	fprintf(stderr, "%s: key is %d, [%p]size is %u.\n", (char *) arg,
		((S_TEST_SEQNODE *) RB_ENTRY(node, S_TEST_SEQNODE, seqnode))->key,
		node, RB_SIZE(node));
	return;
}
